/* ChunkClaim Plugin for Minecraft Bukkit Servers Copyright (C) 2012 Felix Schmidt This file is part of ChunkClaim. ChunkClaim is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ChunkClaim is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with ChunkClaim. If not, see <http://www.gnu.org/licenses/>. */ package com.github.schmidtbochum.chunkclaim; import java.util.Date; import java.util.HashSet; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Animals; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.entity.PoweredMinecart; import org.bukkit.entity.StorageMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerBedEnterEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.InventoryHolder; public class PlayerEventHandler implements Listener { private DataStore dataStore; public PlayerEventHandler(DataStore dataStore) { this.dataStore = dataStore; } //when a player successfully joins the server... @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) void onPlayerJoin(PlayerJoinEvent event) { String playerName = event.getPlayer().getName(); //note login time PlayerData playerData = this.dataStore.getPlayerData(playerName); playerData.lastLogin = new Date(); if(playerData.firstJoin==null) playerData.firstJoin = new Date(); //if (!event.getPlayer().hasPlayedBefore()) //ChunkClaim.plugin.broadcast(ChatColor.LIGHT_PURPLE + "[GLaDOS] " + ChatColor.GREEN +"Welcome " + playerName + ChatColor.GREEN +" to The Colony!"); //event.getPlayer().sendMessage(ChatColor.DARK_RED + "Running ChunkClaim Alpha. ONLY FOR TESTING!"); this.dataStore.savePlayerData(playerName, playerData); } //when a player quits... @EventHandler(priority = EventPriority.HIGHEST) void onPlayerQuit(PlayerQuitEvent event) { Player player = event.getPlayer(); PlayerData playerData = this.dataStore.getPlayerData(player.getName()); //make sure his data is all saved this.dataStore.savePlayerData(player.getName(), playerData); //drop data about this player this.dataStore.clearCachedPlayerData(player.getName()); } //when a player interacts with an entity... @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { if(!ChunkClaim.plugin.config_worlds.contains(event.getPlayer().getLocation().getWorld().getName())) return; Player player = event.getPlayer(); Entity entity = event.getRightClicked(); Chunk chunk = this.dataStore.getChunkAt(entity.getLocation(), null); if(chunk!=null) { if(entity instanceof StorageMinecart || entity instanceof PoweredMinecart || entity instanceof Animals) { if(!chunk.isTrusted(player.getName())) { ChunkClaim.plugin.sendMsg(player,"Not permitted."); event.setCancelled(true); } } } } //block players from entering beds they don't have permission for @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerBedEnter (PlayerBedEnterEvent bedEvent) { Player player = bedEvent.getPlayer(); Block block = bedEvent.getBed(); Chunk chunk = this.dataStore.getChunkAt(block.getLocation(), null); if(chunk!=null) { if(!chunk.isTrusted(player.getName())) { ChunkClaim.plugin.sendMsg(player,"Not permitted."); bedEvent.setCancelled(true); } } } //block use of buckets within other players' claims @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerBucketEmpty (PlayerBucketEmptyEvent bucketEvent) { if(!ChunkClaim.plugin.config_worlds.contains(bucketEvent.getBlockClicked().getWorld().getName())) return; Player player = bucketEvent.getPlayer(); Block block = bucketEvent.getBlockClicked().getRelative(bucketEvent.getBlockFace()); Chunk chunk = this.dataStore.getChunkAt(block.getLocation(), null); if(chunk == null) { bucketEvent.setCancelled(true); return; } if(chunk.isTrusted(player.getName())) { return; } else { ChunkClaim.plugin.sendMsg(player,"You don't have " + chunk.ownerName + "'s permission to build here."); bucketEvent.setCancelled(true); return; } } @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onPlayerBucketFill (PlayerBucketFillEvent bucketEvent) { if(!ChunkClaim.plugin.config_worlds.contains(bucketEvent.getBlockClicked().getWorld().getName())) return; Player player = bucketEvent.getPlayer(); Block block = bucketEvent.getBlockClicked(); Chunk chunk = this.dataStore.getChunkAt(block.getLocation(), null); if(chunk == null) { bucketEvent.setCancelled(true); return; } if(chunk.isTrusted(player.getName())) { return; } else { ChunkClaim.plugin.sendMsg(player,"You don't have " + chunk.ownerName + "'s permission."); bucketEvent.setCancelled(true); return; } } //when a player drops an item @EventHandler(priority = EventPriority.LOWEST) public void onPlayerDrop(PlayerDropItemEvent event) { if(!ChunkClaim.plugin.config_worlds.contains(event.getPlayer().getWorld().getName())) return; Item item = event.getItemDrop(); Material material = item.getItemStack().getType(); //allow dropping books if(material == Material.WRITTEN_BOOK || material == Material.BOOK_AND_QUILL){ return; } else { //ChunkClaim.addLogEntry("Item drop cancelled."); event.setCancelled(true); } } //when a player interacts with the world @EventHandler(priority = EventPriority.LOWEST) void onPlayerInteract(PlayerInteractEvent event) { if(!ChunkClaim.plugin.config_worlds.contains(event.getPlayer().getWorld().getName())) return; Player player = event.getPlayer(); //determine target block. FEATURE: shovel and string can be used from a distance away Block clickedBlock = null; try { clickedBlock = event.getClickedBlock(); //null returned here means interacting with air if(clickedBlock == null || clickedBlock.getType() == Material.SNOW) { //try to find a far away non-air block along line of sight HashSet<Byte> transparentMaterials = new HashSet<Byte>(); transparentMaterials.add(Byte.valueOf((byte)Material.AIR.getId())); transparentMaterials.add(Byte.valueOf((byte)Material.SNOW.getId())); transparentMaterials.add(Byte.valueOf((byte)Material.LONG_GRASS.getId())); clickedBlock = player.getTargetBlock(transparentMaterials, 250); } } catch(Exception e) {//an exception intermittently comes from getTargetBlock(). when it does, just ignore the event return; } //if no block, stop here if(clickedBlock == null) { return; } Material clickedBlockType = clickedBlock.getType(); //apply rules for putting out fires (requires build permission) PlayerData playerData = this.dataStore.getPlayerData(player.getName()); if(event.getClickedBlock() != null && event.getClickedBlock().getRelative(event.getBlockFace()).getType() == Material.FIRE) { Chunk chunk = this.dataStore.getChunkAt(clickedBlock.getLocation(), playerData.lastChunk); if(chunk != null){ playerData.lastChunk = chunk; if(!chunk.isTrusted(player.getName())) { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"You don't have " + chunk.ownerName + "'s permission to build here."); return; } } } //apply rules for containers and crafting blocks else if(ChunkClaim.plugin.config_protectContainers && (clickedBlock.getState() instanceof InventoryHolder || clickedBlockType == Material.WORKBENCH || clickedBlockType == Material.ENDER_CHEST ||clickedBlockType == Material.DISPENSER || clickedBlockType == Material.BREWING_STAND ||clickedBlockType == Material.JUKEBOX ||clickedBlockType == Material.ENCHANTMENT_TABLE)) { Chunk chunk = this.dataStore.getChunkAt(clickedBlock.getLocation(), playerData.lastChunk); if(chunk != null) { playerData.lastChunk = chunk; if(!chunk.isTrusted(player.getName())) { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } } } //otherwise apply rules for buttons and switches else if(ChunkClaim.plugin.config_protectSwitches && (clickedBlockType == null || clickedBlockType == Material.STONE_BUTTON || clickedBlockType == Material.LEVER)) { Chunk chunk = this.dataStore.getChunkAt(clickedBlock.getLocation(), playerData.lastChunk); if(chunk != null) { playerData.lastChunk = chunk; if(!chunk.isTrusted(player.getName())) { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } } } //apply rule for players trampling tilled soil back to dirt (never allow it) //NOTE: that this event applies only to players. monsters and animals can still trample. else if(event.getAction() == Action.PHYSICAL && clickedBlockType == Material.SOIL) { event.setCancelled(true); return; } //apply rule for note blocks and repeaters else if(clickedBlockType == Material.NOTE_BLOCK || clickedBlockType == Material.DIODE_BLOCK_ON || clickedBlockType == Material.DIODE_BLOCK_OFF) { Chunk chunk = this.dataStore.getChunkAt(clickedBlock.getLocation(), playerData.lastChunk); if(chunk != null) { playerData.lastChunk = chunk; if(!chunk.isTrusted(player.getName())) { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } } } //otherwise handle right click (shovel, string, bonemeal) else { //ignore all actions except right-click on a block or in the air Action action = event.getAction(); if(action != Action.RIGHT_CLICK_BLOCK && action != Action.RIGHT_CLICK_AIR) return; //what's the player holding? Material materialInHand = player.getItemInHand().getType(); //check for build permission (ink sac == bone meal, must be a Bukkit bug?) if(materialInHand == Material.INK_SACK || materialInHand == Material.BOAT || materialInHand == Material.MINECART || materialInHand == Material.POWERED_MINECART || materialInHand == Material.STORAGE_MINECART || materialInHand == Material.BOAT) { Chunk chunk = this.dataStore.getChunkAt(clickedBlock.getLocation(), playerData.lastChunk); if(chunk != null) { playerData.lastChunk = chunk; if(!chunk.isTrusted(player.getName())) { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } } else { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } } else if(materialInHand == Material.MONSTER_EGG) { if(ChunkClaim.plugin.config_mobsForCredits && (player.getItemInHand().getDurability() == EntityType.WOLF.getTypeId() || player.getItemInHand().getDurability() == EntityType.OCELOT.getTypeId())) { Chunk chunk = this.dataStore.getChunkAt(clickedBlock.getLocation(), playerData.lastChunk); if(chunk != null) { playerData.lastChunk = chunk; if(!chunk.isTrusted(player.getName())) { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } else { if(playerData.getCredits()>=ChunkClaim.plugin.config_mobPrice) { playerData.credits-=30; ChunkClaim.plugin.sendMsg(player,"You spawned this mob for " + ChunkClaim.plugin.config_mobPrice +" credits. Credits left: " + playerData.getCredits()); return; } else { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not enough credits to spawn a mob ("+ChunkClaim.plugin.config_mobPrice+")."); return; } } } else { event.setCancelled(true); ChunkClaim.plugin.sendMsg(player,"Not permitted."); return; } } else { event.setCancelled(true); return; } } } } }